/* ***** BEGIN LICENSE BLOCK *****
 * Distributed under the BSD license:
 *
 * Copyright (c) 2010, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ***** END LICENSE BLOCK ***** */
define(function(require, exports, module) {
    "use strict";

    require("ace/lib/fixoldbrowsers");

    var config = require("ace/config");
    config.init();

    var env = {};
    var app = {};

    var $ = require("jquery");

    var SFTPController = require("js/views/SFTPController");
    window.SFTPController = new SFTPController();

    //file tabs view;
    window.app = app;
    var tabs = require('js/views/FileTabs');
    window.app.FileTabs = new tabs({});

    // var dom = require("ace/lib/dom");

    var theme = require("ace/theme/textmate");
    var EditSession = require("ace/edit_session").EditSession;
    var UndoManager = require("ace/undomanager").UndoManager;

    var HashHandler = require("ace/keyboard/hash_handler").HashHandler;

    var Renderer = require("ace/virtual_renderer").VirtualRenderer;
    var Editor = require("ace/editor").Editor;
    var MultiSelect = require("ace/multi_select").MultiSelect;
    
    var whitespace = require("ace/ext/whitespace");

    var doclist = require("./doclist");
    window.modelist = require("ace/ext/modelist");
    var layout = require("./layout");
    var TokenTooltip = require("./token_tooltip").TokenTooltip;
    var util = require("./util");
    var saveOption = util.saveOption;
    var fillDropdown = util.fillDropdown;
    var bindCheckbox = util.bindCheckbox;
    var bindDropdown = util.bindDropdown;

    var ElasticTabstopsLite = require("ace/ext/elastic_tabstops_lite").ElasticTabstopsLite;

    var IncrementalSearch = require("ace/incremental_search").IncrementalSearch;

    /*********** create editor ***************************/
    var containerWrapper = document.getElementById("editor-container");
    var container = document.createElement('div');
    container.className = 'editor-class';
    //container.setAttribute("id", self.options.id || "no-id");
    containerWrapper.appendChild(container);

    //crate tab
    //$("#editor-tabs").append('<li data-link="'+self.options.id+'">'+'asdjaalskd'+'</li>');

    // Splitting.
    var Split = require("ace/split").Split;
    var split = new Split(container, theme, 1);
    env.editor = split.getEditor(0);
    split.on("focus", function(editor) {
        env.editor = editor;
        updateUIEditorOptions();
    });
    env.split = split;
    window.envs = []
    window.env = env;
    window.envs.push(env);
    window.ace = env.editor;
    //env.editor.setAnimatedScroll(true);

    // add multiple cursor support to editor
    require("ace/multi_select").MultiSelect(env.editor);
    env.editor.session.setUndoManager(new UndoManager);
    //keep default session for later use
    env.defaultSession = env.editor.session;
    env.noFile = true;

    var consoleEl = document.createElement("div");
    container.parentNode.appendChild(consoleEl);
    consoleEl.style.cssText = "position:fixed; bottom:1px; right:0;\
    border:1px solid #baf; z-index:100";

    var cmdLine = new layout.singleLineEditor(consoleEl);
    cmdLine.editor = env.editor;
    env.editor.cmdLine = cmdLine;

    env.editor.showCommandLine = function(val) {
        this.cmdLine.focus();
        if (typeof val == "string")
            this.cmdLine.setValue(val, 1);
    };

    /**
     * This demonstrates how you can define commands and bind shortcuts to them.
     */
    env.editor.commands.addCommands([{
        name: "gotoline",
        bindKey: {win: "Ctrl-L", mac: "Command-L"},
        exec: function(editor, line) {
            if (typeof line == "object") {
                var arg = this.name + " " + editor.getCursorPosition().row;
                editor.cmdLine.setValue(arg, 1);
                editor.cmdLine.focus();
                return;
            }
            line = parseInt(line, 10);
            if (!isNaN(line))
                editor.gotoLine(line);
        },
        readOnly: true
    }, {
        name: "snippet",
        bindKey: {win: "Alt-C", mac: "Command-Alt-C"},
        exec: function(editor, needle) {
            if (typeof needle == "object") {
                editor.cmdLine.setValue("snippet ", 1);
                editor.cmdLine.focus();
                return;
            }
            var s = snippetManager.getSnippetByName(needle, editor);
            if (s)
                snippetManager.insertSnippet(editor, s.content);
        },
        readOnly: true
    }, {
        name: "focusCommandLine",
        bindKey: "shift-esc|ctrl-`",
        exec: function(editor, needle) { editor.cmdLine.focus(); },
        readOnly: true
    }
    // , {
    //     name: "nextFile",
    //     bindKey: "Ctrl-tab",
    //     exec: function(editor) { doclist.cycleOpen(editor, 1); },
    //     readOnly: true
    // }, {
    //     name: "previousFile",
    //     bindKey: "Ctrl-shift-tab",
    //     exec: function(editor) { doclist.cycleOpen(editor, -1); },
    //     readOnly: true
    // }
    , {
        name: "execute",
        bindKey: "ctrl+enter",
        exec: function(editor) {
            try {
                var r = eval(editor.getCopyText()||editor.getValue());
            } catch(e) {
                r = e;
            }
            editor.cmdLine.setValue(r + "")
        },
        readOnly: true
    }, {
        name: "showKeyboardShortcuts",
        bindKey: {win: "Ctrl-Alt-h", mac: "Command-Alt-h"},
        exec: function(editor) {
            config.loadModule("ace/ext/keybinding_menu", function(module) {
                module.init(editor);
                editor.showKeyboardShortcuts()
            })
        }
    }]);


    env.editor.commands.addCommands(whitespace.commands);

    cmdLine.commands.bindKeys({
        "Shift-Return|Ctrl-Return|Alt-Return": function(cmdLine) { cmdLine.insert("\n"); },
        "Esc|Shift-Esc": function(cmdLine){ cmdLine.editor.focus(); },
        "Return": function(cmdLine){
            var command = cmdLine.getValue().split(/\s+/);
            var editor = cmdLine.editor;
            editor.commands.exec(command[0], editor, command[1]);
            editor.focus();
        }
    });

    cmdLine.commands.removeCommands(["find", "gotoline", "findall", "replace", "replaceall"]);

    var commands = env.editor.commands;
    commands.addCommand({
        name: "save",
        bindKey: {win: "Ctrl-S", mac: "Command-S"},
        exec: function() {
            var id = $('li.active').attr('id').split('_')[0]
                , content = env.editor.session.getValue()
                , fileName = window.app.FileTabs.openTabs.get(id).get('location');

            if(typeof fileName === "undefined") {
                return;
            }
            var text = "Saving file " + fileName
            var writeInterval = setInterval(function(){
                text = text + "."
                env.editor.cmdLine.setValue(text);
            }, 30) 
            //if there is no change don't save but show a fake save animation :)
            var session = window.app.FileTabs.sessions.get(id);
            if(session.get('value') === session.get('session').getValue()) {
                setTimeout(function() {
                    clearInterval(writeInterval);
                    env.editor.cmdLine.setValue(fileName + " successfully saved");
                }, 1500);
                return;
            }
            $.ajax({
                type: 'POST'
                , data: {
                  content: content
                  , name: fileName
                }
                , dataType: 'json'
                , url: '/sftp/write'
                , success: function(resp){
                    clearInterval(writeInterval);
                    if(resp.success){
                        env.editor.cmdLine.setValue(fileName + " successfully saved");
                    }
                    //sync session value with collection
                    session.set('value', content);
                    //change filename span *
                    var span = $('#' + id + '_tab').find('span').first();
                    span.html(session.get('filename'));
                }
            });            
        }
    });

    var keybindings = {
        ace: null, // Null = use "default" keymapping
        vim: require("ace/keyboard/vim").handler,
        emacs: "ace/keyboard/emacs",
        // This is a way to define simple keyboard remappings
        custom: new HashHandler({
            "gotoright":      "Tab",
            "indent":         "]",
            "outdent":        "[",
            "gotolinestart":  "^",
            "gotolineend":    "$"
        })
    };



    /*********** manage layout ***************************/
    var consoleHeight = 20;
    function onResize() {
        var left = env.split.$container.offsetLeft;
        var width = document.documentElement.clientWidth;
        container.style.height = document.documentElement.clientHeight - consoleHeight - 20 + 'px';
        env.split.resize();

        consoleEl.style.width = width - 320 + "px";

        //var editMenu = document.getElementById("menu-toggle");
        //editMenu.style.height = document.documentElement.clientHeight - consoleHeight + "px";
        cmdLine.resize();
    }

    window.onresize = onResize;
    onResize();

    /*********** options panel ***************************/
    var docEl = document.getElementById("doc");
    //var modeEl = document.getElementById("mode");
    var wrapModeEl = document.getElementById("soft_wrap");
    var themeEl = document.getElementById("theme");
    var foldingEl = document.getElementById("folding");
    var selectStyleEl = document.getElementById("select_style");
    var highlightActiveEl = document.getElementById("highlight_active");
    var showHiddenEl = document.getElementById("show_hidden");
    var showGutterEl = document.getElementById("show_gutter");
    var showPrintMarginEl = document.getElementById("show_print_margin");
    var highlightSelectedWordE = document.getElementById("highlight_selected_word");
    var showHScrollEl = document.getElementById("show_hscroll");
    var animateScrollEl = document.getElementById("animate_scroll");
    var softTabEl = document.getElementById("soft_tab");
    var behavioursEl = document.getElementById("enable_behaviours");

    //fillDropdown(docEl, doclist.all);

    //fillDropdown(modeEl, modelist.modes);
    //var modesByName = modelist.modesByName;
    // bindDropdown("mode", function(value) {
    //     env.editor.session.setMode(modesByName[value].mode || modesByName.text.mode);
    //     env.editor.session.modeName = value;
    // });

    doclist.history = doclist.docs.map(function(doc) {
        return doc.name;
    });
    doclist.history.index = 0;
    doclist.cycleOpen = function(editor, dir) {

        var h = this.history
        h.index += dir;
        if (h.index >= h.length) 
            h.index = 0;
        else if (h.index <= 0)
            h.index = h.length - 1;
        var s = h[h.index];
        docEl.value = s;
        docEl.onchange();
        h.index
    }
    doclist.addToHistory = function(name) {
        var h = this.history
        var i = h.indexOf(name);
        if (i != h.index) {
            if (i != -1)
                h.splice(i, 1);
            h.index = h.push(name);
        }
    }

    // bindDropdown("doc", function(name) {
    //     doclist.loadDoc(name, function(session) {
    //         if (!session)
    //             return;
    //         doclist.addToHistory(session.name);
    //         session = env.split.setSession(session);
    //         whitespace.detectIndentation(session);
    //         updateUIEditorOptions();
    //         env.editor.focus();
    //     });
    // });
    
        doclist.loadDoc("JavaScript", function(session) {
            if (!session)
                return;
            doclist.addToHistory(session.name);
            session = env.split.setSession(session);
            whitespace.detectIndentation(session);
            updateUIEditorOptions();
            env.editor.focus();
        });    


    function updateUIEditorOptions() {
        var editor = env.editor;
        var session = editor.session;

        session.setFoldStyle(foldingEl.value);

        // saveOption(docEl, session.name);
        // saveOption(modeEl, session.modeName || "text");
        saveOption(wrapModeEl, session.getUseWrapMode() ? session.getWrapLimitRange().min || "free" : "off");

        saveOption(selectStyleEl, editor.getSelectionStyle() == "line");
        saveOption(themeEl, editor.getTheme());
        saveOption(highlightActiveEl, editor.getHighlightActiveLine());
        saveOption(showHiddenEl, editor.getShowInvisibles());
        saveOption(showGutterEl, editor.renderer.getShowGutter());
        saveOption(showPrintMarginEl, editor.renderer.getShowPrintMargin());
        saveOption(highlightSelectedWordE, editor.getHighlightSelectedWord());
        saveOption(showHScrollEl, editor.renderer.getHScrollBarAlwaysVisible());
        saveOption(animateScrollEl, editor.getAnimatedScroll());
        saveOption(softTabEl, session.getUseSoftTabs());
        saveOption(behavioursEl, editor.getBehavioursEnabled());
    }

    // event.addListener(themeEl, "mouseover", function(e){
    //     this.desiredValue = e.target.value;
    //     if (!this.$timer)
    //         this.$timer = setTimeout(this.updateTheme);
    // });

    // event.addListener(themeEl, "mouseout", function(e){
    //     this.desiredValue = null;
    //     if (!this.$timer)
    //         this.$timer = setTimeout(this.updateTheme, 20);
    // });

    themeEl.updateTheme = function(){
        env.split.setTheme(themeEl.desiredValue || themeEl.selectedValue);
        themeEl.$timer = null;
    };

    bindDropdown("theme", function(value) {
        if (!value)
            return;
        env.editor.setTheme(value);
        themeEl.selectedValue = value;
    });

    bindDropdown("keybinding", function(value) {
        env.editor.setKeyboardHandler(keybindings[value]);
    });

    bindDropdown("fontsize", function(value) {
        env.split.setFontSize(value);
    });

    bindDropdown("folding", function(value) {
        env.editor.session.setFoldStyle(value);
        env.editor.setShowFoldWidgets(value !== "manual");
    });

    bindDropdown("soft_wrap", function(value) {
        var session = env.editor.session;
        var renderer = env.editor.renderer;
        switch (value) {
            case "off":
                session.setUseWrapMode(false);
                renderer.setPrintMarginColumn(80);
                break;
            case "free":
                session.setUseWrapMode(true);
                session.setWrapLimitRange(null, null);
                renderer.setPrintMarginColumn(80);
                break;
            default:
                session.setUseWrapMode(true);
                var col = parseInt(value, 10);
                session.setWrapLimitRange(col, col);
                renderer.setPrintMarginColumn(col);
        }
    });

    bindCheckbox("select_style", function(checked) {
        env.editor.setSelectionStyle(checked ? "line" : "text");
    });

    bindCheckbox("highlight_active", function(checked) {
        env.editor.setHighlightActiveLine(checked);
    });

    bindCheckbox("show_hidden", function(checked) {
        env.editor.setShowInvisibles(checked);
    });

    bindCheckbox("display_indent_guides", function(checked) {
        env.editor.setDisplayIndentGuides(checked);
    });

    bindCheckbox("show_gutter", function(checked) {
        env.editor.renderer.setShowGutter(checked);
    });

    bindCheckbox("show_print_margin", function(checked) {
        env.editor.renderer.setShowPrintMargin(checked);
    });

    bindCheckbox("highlight_selected_word", function(checked) {
        env.editor.setHighlightSelectedWord(checked);
    });

    bindCheckbox("show_hscroll", function(checked) {
        env.editor.renderer.setHScrollBarAlwaysVisible(checked);
    });

    bindCheckbox("animate_scroll", function(checked) {
        env.editor.setAnimatedScroll(checked);
    });

    bindCheckbox("soft_tab", function(checked) {
        env.editor.session.setUseSoftTabs(checked);
    });

    bindCheckbox("enable_behaviours", function(checked) {
        env.editor.setBehavioursEnabled(checked);
    });

    bindCheckbox("fade_fold_widgets", function(checked) {
        env.editor.setFadeFoldWidgets(checked);
    });
    bindCheckbox("read_only", function(checked) {
        env.editor.setReadOnly(checked);
    });

    bindDropdown("split", function(value) {
        var sp = env.split;
        if (value == "none") {
            sp.setSplits(1);
        } else {
            var newEditor = (sp.getSplits() == 1);
            sp.setOrientation(value == "below" ? sp.BELOW : sp.BESIDE);
            sp.setSplits(2);

            if (newEditor) {
                var session = sp.getEditor(0).session;
                var newSession = sp.setSession(session, 1);
                newSession.name = session.name;
            }
        }
    });


    bindCheckbox("elastic_tabstops", function(checked) {
        env.editor.setOption("useElasticTabstops", checked);
    });

    var iSearchCheckbox = bindCheckbox("isearch", function(checked) {
        env.editor.setOption("useIncrementalSearch", checked);
    });

    env.editor.addEventListener('incrementalSearchSettingChanged', function(event) {
        iSearchCheckbox.checked = event.isEnabled;
    });


    function synchroniseScrolling() {
        var s1 = env.split.$editors[0].session;
        var s2 = env.split.$editors[1].session;
        s1.on('changeScrollTop', function(pos) {s2.setScrollTop(pos)});
        s2.on('changeScrollTop', function(pos) {s1.setScrollTop(pos)});
        s1.on('changeScrollLeft', function(pos) {s2.setScrollLeft(pos)});
        s2.on('changeScrollLeft', function(pos) {s1.setScrollLeft(pos)});
    }

    bindCheckbox("highlight_token", function(checked) {
        var editor = env.editor;
        if (editor.tokenTooltip && !checked) {
            editor.tokenTooltip.destroy();
            delete editor.tokenTooltip;
        } else if (checked) {
            editor.tokenTooltip = new TokenTooltip(editor);
        }
    });

    /************** dragover ***************************/
    // event.addListener(container, "dragover", function(e) {
    //     var types = e.dataTransfer.types;
    //     if (types && Array.prototype.indexOf.call(types, 'Files') !== -1)
    //         return event.preventDefault(e);
    // });

    // event.addListener(container, "drop", function(e) {
    //     var file;
    //     try {
    //         file = e.dataTransfer.files[0];
    //         if (window.FileReader) {
    //             var reader = new FileReader();
    //             reader.onload = function() {
    //                 var mode = modelist.getModeForPath(file.name);

    //                 env.editor.session.doc.setValue(reader.result);
    //                 modeEl.value = mode.name;
    //                 env.editor.session.setMode(mode.mode);
    //                 env.editor.session.modeName = mode.name;
    //             };
    //             reader.readAsText(file);
    //         }
    //         return event.preventDefault(e);
    //     } catch(err) {
    //         return event.stopEvent(e);
    //     }
    // });



    var StatusBar = require("ace/ext/statusbar").StatusBar;
    new StatusBar(env.editor, cmdLine.container);


    // var Emmet = require("ace/ext/emmet");
    // net.loadScript("https://rawgithub.com/nightwing/emmet-core/master/emmet.js", function() {
    //     Emmet.setCore(window.emmet);
    //     env.editor.setOption("enableEmmet", true);
    // })


    require("ace/placeholder").PlaceHolder;

    var snippetManager = require("ace/snippets").snippetManager
    // var jsSnippets = require("ace/snippets/javascript");
    // window.snippetManager = snippetManager
    // saveSnippets()

    // function saveSnippets() {
    //     jsSnippets.snippets = snippetManager.parseSnippetFile(jsSnippets.snippetText);
    //     snippetManager.register(jsSnippets.snippets, "javascript")
    // }

env.editSnippets = function() {
    var sp = env.split;
    if (sp.getSplits() == 2) {
        sp.setSplits(1);
        return;
    }
    sp.setSplits(1);
    sp.setSplits(2);
    sp.setOrientation(sp.BESIDE);
    var editor = sp.$editors[1];
    var id = sp.$editors[0].session.$mode.$id || "";
    var m = snippetManager.files[id];
    if (!doclist["snippets/" + id]) {
        var text = m.snippetText;
        var s = doclist.initDoc(text, "", {});
        s.setMode("ace/mode/snippets");
        doclist["snippets/" + id] = s
    }
    editor.on("blur", function() {
        m.snippetText = editor.getValue();
        snippetManager.unregister(m.snippets);
        m.snippets = snippetManager.parseSnippetFile(m.snippetText, m.scope);
        snippetManager.register(m.snippets);
    })
    sp.$editors[0].once("changeMode", function() {
        sp.setSplits(1);
    })
    editor.setSession(doclist["snippets/" + id], 1);
    editor.focus();
}

require("ace/ext/language_tools");
env.editor.setOptions({
    enableBasicAutocompletion: true,
    enableSnippets: true
})

    ace.commands.bindKey("Tab", function(editor) {
        var success = snippetManager.expandWithTab(editor);
        if (!success)
            editor.execCommand("indent");
    });

});
